#include "windowsurface.h"
#include "qgraphicssystem.h"


WindowSurface::WindowSurface(QWidget *window, OGraphicsSystem *system)
    : QWindowSurface(window), m_system(system)
{
    quint32 parentId = system->m_ids.value(window->parentWidget(), 0);

    Request request(Request::CreateWindowRequest, parentId);
    system->sendRequest(request);

    Response response;
    system->waitForResponse(response);
    m_id = response.id;

    m_system->m_surfaces.insert(m_id, this);
    m_system->m_ids.insert(window, m_id);
}

WindowSurface::~WindowSurface()
{
    Request request(Request::DestroyWindowRequest, m_id);
    m_system->sendRequest(request);
    m_system->m_surfaces.remove(m_id);
    m_system->m_ids.remove(window());
}

QPaintDevice *WindowSurface::paintDevice()
{
    qDebug() << "WINDOW: paint device" << m_image.size();
    return &m_image;
}

void WindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
{
    Q_UNUSED(widget);
    Q_UNUSED(region);
    Q_UNUSED(offset);
    qDebug() << "WINDOW: flush";
    // send an update request to the server
    Request request(Request::UpdateWindowRequest, m_id); // ### rect
    m_system->sendRequest(request);
    // we don't expect any response

    m_image.save(QString("c:\\home\\src\\builds\\image-%1.png").arg(m_id));
}

void WindowSurface::setGeometry(const QRect &rect)
{
    qDebug() << "WINDOW: setGeometry";
    QWindowSurface::setGeometry(rect);
    qDebug() << "WINDOW: geometry" << geometry();

    // create or resize the shared memory
    qint32 byteCount = rect.width() * rect.height() * sizeof(quint32); // ### server should hold the pixel format
    qDebug() << "WINDOW: byte count" << byteCount;
    if (byteCount > m_shared.size()) {
        if (!m_shared.key().isEmpty())
            m_shared.setKey(QString()); // detach
        m_shared.setKey(QString::number(m_id));
        if (!m_shared.create(byteCount) && !m_shared.attach())
            qWarning() << m_shared.errorString() << m_shared.key();
        qDebug() << "WINDOW: data" << m_shared.data() << "key" << m_shared.key();
        Q_ASSERT(m_shared.data());
    }

    Request request(Request::SetWindowGeometryRequest, m_id, 0, rect);
    m_system->sendRequest(request);
}

bool WindowSurface::scroll(const QRegion &area, int dx, int dy)
{
    // the server doesn't have scroll
    return QWindowSurface::scroll(area, dx, dy);
}

void WindowSurface::beginPaint(const QRegion &region)
{
    Q_UNUSED(region);
    qDebug() << "WINDOW: begin paint" << m_id << geometry();
    // lock the surface shared memory before painting
    if (m_shared.lock() && m_shared.data())
        m_image = QImage((uchar*)m_shared.data(), geometry().width(), geometry().height(), QImage::Format_ARGB32);
    else
        qDebug() << m_shared.errorString();
    qDebug() << "WINDOW: image" << m_image.size() << "geometry" << geometry() << "data" << m_shared.data() << "key" << m_shared.key();
}

void WindowSurface::endPaint(const QRegion &region)
{
    Q_UNUSED(region);
    qDebug() << "WINDOW: end paint";
    // unlock the surface shared memory after painting
    // also make sure that the paint device is invalid
    if (m_shared.unlock())
        m_image = QImage();
    else
        qDebug() << "WINDOW: failed to unlock shared memory";
}


void WindowSurface::setVisible(bool visible)
{
    qDebug() << "WINDOW: setVisible()" << visible;
    Request request(visible ? Request::ShowWindowRequest : Request::HideWindowRequest, m_id);
    m_system->sendRequest(request);
}

Qt::WindowFlags WindowSurface::setWindowFlags(Qt::WindowFlags type)
{
    return window_flags = type;
}

Qt::WindowFlags WindowSurface::windowFlags() const
{
    return window_flags;
}


void WindowSurface::raise()
{
    qDebug() << "WINDOW: raise()";
    Request request(Request::RaiseWindowRequest, m_id);
    m_system->sendRequest(request);

}

void WindowSurface::lower()
{
    qDebug() << "WINDOW: lower()";
    Request request(Request::LowerWindowRequest, m_id);
    m_system->sendRequest(request);

}
